// pub mod ma;
// pub mod bigvolume;
// pub mod shortline;
// pub mod smalliddle;
pub mod bottom_fishing;
pub mod flat_lines_breakout;
pub mod sharp_drop_rebounce;
// pub mod upstop_return;
pub mod util;

use std::collections::HashMap;

use anyhow::Result;
use fudata::db;
use fudata::model::security;
use fudata::model::security::Market;
use fudata::model::security::Security;
// use bigvolume::BigVolumeStrategy;
use fudata::model::trade::trade_strategy::TradeStrategy;
use fudata::model::kline::Klt;
use fudata::model::trade::trade_strategy_data::TradeStrategyData;
use fudata::model::trade::trade_strategy_data::Short;
use fudata::model::trade::trade_strategy_data::Long;
use fudata::round2;
use once_cell::sync::Lazy;
use serde::Deserialize;
use serde::Serialize;
// use shortline::ShortlineStrategy;
// use smalliddle::SmallilldeStrategy;
use surrealdb::sql::Thing;

trait Strategy {
    async fn backtest(&self, security_id: &str) -> Result<BacktestResult>;
}

#[derive(Debug, Clone)]
struct BacktestResult {
    profit: f64,
    win_rate: f64,
    avg_holding_days: f64,
}

#[derive(Debug, Clone)]
pub struct StrategyPerformance {
    buyorder_id: String,
    buy_price: f64,

    sellorder_id: String,
    sell_price: f64,

    volume: u16,
    message: String,
}
impl StrategyPerformance {
    fn cross_profit(&self) -> f64 {
        round2((self.sell_price - self.buy_price) * (self.volume as f64))
    }

    fn cross_profit_percent(&self) -> f64 {
        round2(((self.sell_price - self.buy_price) / self.buy_price) * 100.0)
    }
    /// 计算总费用
    fn fee(&self) -> f64 {
        let commission_rate = 0.000085; // 佣金费率为万分之0.85
        let stamp_tax_rate = 0.001; // 印花税率为千分之一
        let transfer_fee_rate = 0.00002; // 过户费率为万分之0.2

        let buy_cost = self.buy_price * (self.volume as f64);
        let sell_cost = self.sell_price * (self.volume as f64);

        let buy_commission_fee = buy_cost * commission_rate;
        let sell_commission_fee = sell_cost * commission_rate;
        let sell_stamp_tax = sell_cost * stamp_tax_rate;
        let buy_transfer_fee = buy_cost * transfer_fee_rate;
        let sell_transfer_fee = sell_cost * transfer_fee_rate;

        buy_commission_fee +
            sell_commission_fee +
            sell_stamp_tax +
            buy_transfer_fee +
            sell_transfer_fee
    }
}

#[derive(Debug, Serialize, Deserialize, Default, Clone)]
struct StrategyPerformanceSummary {
    // info!(
    //     "{} tpf: {} tfe:{} ttd: {} wnr: {:.2}% acr: {:.2}% anr: {:.2}% plr: {:.2}",
    //     security_id,
    //     round2(total_cross_profit),
    //     round2(total_fee),
    //     total_trades,
    //     round2(win_rate * 100.0),
    //     round2(average_cross_return),
    //     round2(average_net_return),
    //     round2(profit_loss_ratio)
    // );

    pub security_id: String,
    pub total_profit: f64,
    pub total_loss: f64,
    pub total_fee: f64,
    pub total_trades: usize,
    pub win_rate: f64,
    pub average_cross_return: f64,
    pub average_net_return: f64,
    pub profit_loss_ratio: f64,

    // klines summary
}

pub fn calculate_strategy_performance(
    security_id: &str,
    stpfs: &[StrategyPerformance]
) -> Option<StrategyPerformanceSummary> {
    if stpfs.len() > 0 {
        let total_profit: f64 = stpfs
            .iter()
            .filter(|t| t.cross_profit() > 0.0)
            .map(|t| t.cross_profit())
            .sum();

        let total_loss: f64 = stpfs
            .iter()
            .filter(|t| t.cross_profit() < 0.0)
            .map(|t| t.cross_profit())
            .sum();

        let total_fee: f64 = stpfs
            .iter()
            .map(|t| t.fee())
            .sum();

        let total_trades = stpfs.len();
        let winning_trades = stpfs
            .iter()
            .filter(|t| t.cross_profit() > 0.0)
            .count();
        let losing_trades = stpfs
            .iter()
            .filter(|t| t.cross_profit() < 0.0)
            .count();
        let win_rate = if total_trades > 0 {
            (winning_trades as f64) / (total_trades as f64)
        } else {
            0.0
        };

        let average_cross_return = if total_trades > 0 {
            (total_profit + total_loss) / (total_trades as f64)
        } else {
            0.0
        };

        let average_net_return = if total_trades > 0 {
            (total_profit + total_loss - total_fee) / (total_trades as f64)
        } else {
            0.0
        };

        let profit_loss_ratio = if losing_trades > 0 {
            total_profit / total_loss.abs()
        } else {
            99.99
        };

        Some(StrategyPerformanceSummary {
            security_id: security_id.to_owned(),
            total_profit: round2(total_profit),
            total_loss: round2(total_loss),
            total_fee: round2(total_fee),
            total_trades,
            win_rate: round2(win_rate * 100.0),
            average_cross_return: round2(average_cross_return),
            average_net_return: round2(average_net_return),
            profit_loss_ratio: round2(profit_loss_ratio),
        })
    } else {
        None
    }
    // 更多复杂的计算如夏普比率、最大回撤等需要历史数据和更多的统计分析。
}
pub fn print_strategy_performance_summary(sec_perfs: HashMap<String, Vec<StrategyPerformance>>) {
    let mut perf_sums = Vec::new();
    for (k, v) in sec_perfs {
        if let Some(perf_sum) = calculate_strategy_performance(&k, &v) {
            perf_sums.push(perf_sum);
        }
    }
    perf_sums.sort_by(|a, b|
        b.profit_loss_ratio
            .partial_cmp(&a.profit_loss_ratio)
            .unwrap_or(std::cmp::Ordering::Equal)
            .then_with(|| b.win_rate.partial_cmp(&a.win_rate).unwrap_or(std::cmp::Ordering::Equal))
    );

    println!(
        "\n#,security_id, profit_loss_ratio, win_rate, total_profit, total_loss, total_fee, total_trades"
    );
    for (idx, perf_sum) in perf_sums.iter().enumerate() {
        println!(
            "{idx}, {}, {:.2}, {:.2}, {:.2}, {:.2}, {:.2}, {:.2}",
            perf_sum.security_id,
            perf_sum.profit_loss_ratio,
            perf_sum.win_rate,
            perf_sum.total_profit,
            perf_sum.total_loss,
            perf_sum.total_fee,
            perf_sum.total_trades
        );
    }
}
/// 根据投资金额和价格计算成交量，并向上取整至最接近的100的倍数
pub fn calculate_volume(price: f64, investment_amount: f64) -> f64 {
    if price == 0.0 {
        panic!("Price cannot be zero.");
    }

    let volume = investment_amount / price;
    let rounded_volume = (volume.ceil() / 100.0).ceil() * 100.0;
    rounded_volume
}
pub async fn run_backtests(securities: &[&str]) -> Result<()> {
    for security_id in securities {
        println!("Backtesting for security: {}", security_id);
        // for strategy in &self.0 {
        //     let result = strategy.backtest(security_id).await?;
        //     println!("Strategy result: {:?}", result);
        // }

        // let result = BigVolumeStrategy.backtest(security_id).await?;
        // println!("BigVolumeStrategy result: {:?}", result);

        // let result = ShortlineStrategy.backtest(security_id).await?;
        // println!("ShortlineStrategy result: {:?}", result);

        // let result = SmallilldeStrategy.backtest(security_id).await?;
        // println!("ShortlineStrategy result: {:?}", result);
    }

    Ok(())
}

// Create a hardcode vector of trade-strategies
pub static TRADE_STRATEGIES: Lazy<Vec<TradeStrategy>> = Lazy::new(|| {
    vec![
        TradeStrategy {
            id: Some(Thing::from(("trade_strategy", "strategy.5.1"))),
            klt: Klt::M005,
            seqno: 1,
            name: Some("15分钟K线的1号交易策略".to_string()),
            desc: Some("15分钟K线的1号交易策略".to_string()),
            script_verified: Some(true),
            is_gen_auto_trade_command: Some(false),
            data: Some(
                TradeStrategyData::Short(Short { volume: 500, desc: "short@mod.rs".to_string() })
            ),
            ..Default::default()
        },
        TradeStrategy {
            id: Some(Thing::from(("trade_strategy", "strategy.5.2"))),
            klt: Klt::M005,
            seqno: 1,
            name: Some("60分钟K线的1号交易策略".to_string()),
            desc: Some("60分钟K线的1号交易策略".to_string()),
            script_verified: Some(true),
            is_gen_auto_trade_command: Some(false),
            data: Some(
                TradeStrategyData::Short(Short { volume: 500, desc: "short@mod.rs".to_string() })
            ),
            ..Default::default()
        },
        TradeStrategy {
            id: Some(Thing::from(("trade_strategy", "strategy.5.3"))),
            klt: Klt::M005,
            seqno: 1,
            name: Some("日K线的1号交易策略".to_string()),
            desc: Some("日K线的1号交易策略".to_string()),
            script_verified: Some(true),
            is_gen_auto_trade_command: Some(false),
            data: Some(
                TradeStrategyData::Long(Long { volume: 500, desc: "long@mod.rs".to_string() })
            ),
            ..Default::default()
        }
    ]
});

pub async fn get_strategy_test_securities(
    hardcode: bool,
    market: Option<Market>,
    type_: Option<security::SecurityType>,
    pi: u16,
    pn: u16
) -> Vec<Security> {
    if !hardcode {
        let all_securities = db::security
            ::select(
                &market, //&Some(Market::SH),
                type_, // Some(security::SecurityType::STK),
                None,
                Some("id ASC"),
                pi,
                pn //MAX_STK_SECURITY
            ).await
            .unwrap();
        // 使用迭代器过滤出 security_id 以 "SH.SZ.60" 开头的对象,如果您想要拥有所有权而非引用：
        return all_securities
            .into_iter()
            .filter(|security| {
                let security_id = security.id_raw();
                security_id.starts_with("SH.STK.60") ||
                    security_id.starts_with("SZ.STK.30") ||
                    security_id.starts_with("SZ.STK.00") ||
                    security_id.starts_with("SH.ETF") ||
                    security_id.starts_with("SZ.ETF")
            })
            .collect();
    } else {
        return vec![
            Security {
                id: Some(Thing::from(("security", "SZ.STK.300363"))),
                ..Default::default()
            },
            Security {
                id: Some(Thing::from(("security", "SZ.STK.002648"))),
                ..Default::default()
            },
            Security {
                id: Some(Thing::from(("security", "SH.STK.603085"))),
                ..Default::default()
            },
            Security {
                id: Some(Thing::from(("security", "SH.STK.601555"))),
                ..Default::default()
            }
        ];
    }
}
